//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1995-2003  Microsoft Corporation

Module Name: dispatcher.h

Abstract:


Notes:


--*/
//
//
// (C) Copyright 2007 Marvell International Ltd.
//  All Rights Reserved
//

#pragma once

//
// OS side interface
//
#include <windows.h>

//---------------
// log messages
//---------------
#ifdef GSM0710_LOG_MSG
    #ifdef SENDLOGTOFILE
        #include "LogToFile.h"
        #define SENDLOG(p1)     SendLogToFile p1
    #else
        #define SENDLOG(p1)     NKDbgPrintfW p1
    #endif    // SENDLOGTOFILE
#else
    #define SENDLOG(p1)
#endif        // GSM0710_LOG_MSG

#ifdef GSM0710_ERR_MSG
    #ifdef SENDLOGTOFILE
        #include "LogToFile.h"
        #define SENDERR(p1)     SendLogToFile p1
    #else
        #define SENDERR(p1)     NKDbgPrintfW p1
    #endif    // SENDLOGTOFILE
#else
    #define SENDERR(p1)         
#endif        // GSM0710_ERR_MSG

//----------------------------
// gsm 07.10 related defines
//----------------------------

// Complete Frame time-out
#define COMPLETEFRAME_TIMEOUT   3000

// time allowed between FCOFF and FCON 
//
// rem : if this time elapsed the radio will be reseted
#define TIME_OUT_BEFORE_RESET   60000        // ms

// UIH max data lenght
//#define UIH_MAX_DATA 64
#define UIH_MAX_DATA 98

#if UIH_MAX_DATA < 0x7F
    #define UIH_MAX_DATA_BLEN   UIH_MAX_DATA
#else
    #define UIH_MAX_DATA_BLEN   0x7F
#endif

#define GSM0710_BASIC_FLAG      0xF9
#define GSM0710_ADVANCED_FLAG   0x7E
#define GSM0710_CTRL_OCTET      0x7D

#define FRAME_HEADER_SIZE       2
#define FRAME_SIZE_MIN          (FRAME_HEADER_SIZE + 1)

// pre defined DLCI
//-------------------
#define CTRL_CHANEL_DLCI        0x00
#define INVALID_DLCI            0xFF

// bit masks
//-----------
#define EA_BIT          1
#define CLEAR_EA_MASK   0xFE
#define SET_EA_MASK     0x01

#define CR_BIT          2
#define CLEAR_CR_MASK   0xFD
#define SET_CR_MASK     0x02

#define PF_BIT          5
#define CLEAR_PF_MASK   0xEF
#define SET_PF_MASK     0x10

// control field (P/F bit set)
//------------------------------
#define CTRL_FIELD_SABM     (0x2F | SET_PF_MASK)
#define CTRL_FIELD_UA       (0x63 | SET_PF_MASK)
#define CTRL_FIELD_DM       (0x0F | SET_PF_MASK)
#define CTRL_FIELD_DISC     (0x43 | SET_PF_MASK)
#define CTRL_FIELD_UIH      (0xEF | SET_PF_MASK)

// control chanel:  0
// DLCI:            [1-63]
//-----------------------------
#define MAX_CHANEL_ID       64

#define CONTROL_CHANEL      0
#define FIRST_USER_CHANEL   1
#define NULL_CHANEL_ID      0xFF

// parameter negociation
//-----------------------

#ifdef GSM0710_UNITARY_TESTS

// time out value (ms)
#define GSM0710_T1  1000
#define GSM0710_T2  1500
#define GSM0710_T3  3000

#else

// AT cmd send by Mux
#define AT_CMD_SIZE 256
#define OK_RSP "\r\nOK\r\n"

// time out value (ms)
#define GSM0710_T1   1000    
#define GSM0710_T2   1500    
#define GSM0710_T3  10000    

#endif        // GSM0710_UNITARY_TESTS


//-----------------------
// Wake up procedure
//-----------------------
#define WAKE_UP_SEND_FLAG_INTERVAL      6   // every WAKE_UP_SEND_FLAG_INTERVAL ms Flag will be send

//-------------------------------------
// underlying COM port related defines
//-------------------------------------
#define DEFAULT_COM_MASK    (EV_RXCHAR | EV_RLSD | EV_ERR | EV_BREAK | EV_RING)

// CChanel class declaration forwarding
//---------------------------------------
class CChanel;
class CCtrlChanel;

typedef struct
{
    BYTE  bFlag;
    DWORD dwMaxDataSize;
} tFrameParam;

enum tPowerMgt
{
    OPERATIONAL,
    WAKING_UP_TE_INITIATIVE,
    WAKING_UP_MS_INITIATIVE,
    POWER_SAVING,
    WAKE_UP_TIME_OUTED,
};

class CDispatcher
{
public :
    CDispatcher();
    ~CDispatcher();

    void ResetInternalData();
    bool ResetFixedLocalRate(PTCHAR szComName);

    bool ReadComEvent();
    void CloseComPort();
    DWORD InitPort(PTCHAR szComName);
    bool ReInit(PTCHAR szComName, DWORD dwBaudRate);

    bool OpenComPort(PTCHAR szComName, DWORD dwBaudRate);

    bool Init();
    bool ReinitAll();

    void TerminateAll();

    void Terminate();
    void TryTerminate();
    void TerminateSerialIntf();

    bool operator!();
    bool IsOnlyCtrlChannelOpen();

    bool IsDlciAlreadyBooked(CChanel *pChnl);    
    bool Register(CChanel *pChnl, tFrameParam* pFP);
    bool Unregister(CChanel *pChnl);

    inline void SetPowerSavingMode() { InterlockedExchange(&m_lPowerState, POWER_SAVING); };
    void BroadcastChnlIdleStatus();

    // synchro and threading
    //-----------------------
    inline void LockSend()        { EnterCriticalSection(&m_csSend); };
    inline void UnlockSend()    { LeaveCriticalSection(&m_csSend); };
    DWORD Send(BYTE* pFrame, DWORD cbFrame); 

    // module on/off
    //---------------
    HANDLE m_hRebootOKEv;
    HANDLE m_hRebootKOEv;

    bool SwitchRadioOff();
    bool SwitchRadioOff(bool bCloseCOMPort);
    bool SwitchRadioOn();
    bool ResetRadio();

    bool m_bResetRequired;

    void RequestResetIn(DWORD m_dwTimeOutBeforeReset);
    void CancelResetRequest();

    // gsm 07.10 related
    //--------------------
    bool NegotiateService(BYTE bDlci);
    bool SetModemStatus(BYTE bDlci, BYTE v24Sig);
    bool SendModemStatus(BYTE bDlci, BYTE v24Sig);
    bool EnterPowerSavingMode();

    // nb of connected channels
    long m_lConnectedChanelNb;

private :
    bool m_bIsOk;
    bool m_bIsInitialized;
    LONG m_lPowerState;

    BYTE m_bFrameFlag; // basic or advanced

    DWORD m_cbMaxFrameData; //max number of octets in I-field (not including escape octets)

    // synchro and threading
    //-----------------------
    DWORD m_dwTimeOut;

    bool m_bTerminate;
    bool m_bTerminateAll;

    HANDLE m_hComPort;

    HANDLE m_hSenseComTh;
    HANDLE m_hTimeOutTh;
    HANDLE m_hWakeUpTh;

    HANDLE m_hLaunchTimeOutEv;
    HANDLE m_hCancelTimeOutEv;
    HANDLE m_hGoAheadEv;
    HANDLE m_hWokenUpEv;
    HANDLE m_hLaunchWakeUpEv;

    CRITICAL_SECTION m_csSend;

    friend DWORD WINAPI SenseComTh( PVOID pContext );
    friend DWORD WINAPI TimeOutTh( PVOID pContext );
    friend DWORD WINAPI WakeUpTh( PVOID pContext );

    // module on/off
    //---------------
    friend DWORD WINAPI ResetRadioTh( PVOID pContext );

    DWORD m_dwTimeOutBeforeReset;

    HANDLE m_hCancelResetEv;

    void WakeupResponse();
    
    #define GET_DLCI(bAdd) (bAdd >> 2)

    // registered chanels
    //---------------------
    CChanel *m_ppChanel[MAX_CHANEL_ID];

    // control chanel
    CCtrlChanel *m_pCtrlChanel;

    // Declarations for parsing the received data
    //----------------------------------
    enum eParseState
    {
        WAIT_FRAME,
        START_FRAME,        
        READ_FRAME_HEADER,
        READ_FRAME_LENGTH,
        READ_FRAME_DATA,        
        READ_FRAME_COMPLETE,
        READ_FRAME_ERROR
    };

    typedef DWORD (CDispatcher::* READFN) (void* pParseParam, BYTE* pRxBuffer, DWORD cbRxBuffer);

    typedef struct
    {
        eParseState State;         //parser state
        BOOL        bEndOfFrame;   //received closing flag for a frame
        READFN      pfnReadFrame;  //function to read frame data into pFrameBuf.
                                   //Different for Basic and Advanced cases
        union
        {
            BOOL  bEsc;          //byte is escaped (Advanced mode)  
            DWORD cbLength;      //length of data field (Basic mode)
        } Param;
        
        DWORD       cbData;      //number of frame bytes in pFrameBuf 
        BYTE*       pFrameBuf;   //contains address, control, I field (if any) and FCS
        DWORD       cbFrameBuf;  //size alloc'd for pFrameBuf
    } tParseData;

    DWORD ReadAdvancedModeFrame(void* pParseParam, BYTE* pRxBuffer, DWORD cbRxBuffer);
    DWORD ReadBasicModeFrame(void* pParseParam, BYTE* pRxBuffer, DWORD cbRxBuffer);
    BOOL  ConfigureModemBaudRate(DWORD dwTargetBaudRate);
    
    void ParseRecBytes(tParseData* pPD, BYTE* pRxBuffer, DWORD cbRxBuffer);
};
